#pragma once

#include <nxos/defines.h>
#include <nxos/types.h>
#include <nxos/error.h>
#include <stdint.h>

/**
 * 定义net宏
 */

#ifndef LWIP_SOCKET

 //* Supported address families.
#define AF_INET  2  //* internetwork: UDP, TCP, etc.
#if SUPPORT_IPV6
#define AF_INET6 23 // Internetwork Version 6
#endif

#define IP4ADDR_STRLEN_MAX  16

/* Flags we can use with send and recv. */
#define MSG_PEEK       0x01    /* Peeks at an incoming message */
#define MSG_WAITALL    0x02    /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */
#define MSG_OOB        0x04    /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */
#define MSG_DONTWAIT   0x08    /* Nonblocking i/o for this operation only */
#define MSG_MORE       0x10    /* Sender will send more */
#define MSG_NOSIGNAL   0x20    /* Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. */

#define PF_INET         AF_INET
#define PF_INET6        AF_INET6
#define PF_UNSPEC       AF_UNSPEC

 //* Socket types.
#define SOCK_STREAM 1   //* TCP, stream (connection) socket
#define SOCK_DGRAM  2   //* UDP, datagram (conn.less) socket
#define SOCK_RAW    3

#define IP_PROTO_ICMP    1
#define IP_PROTO_IGMP    2
#define IP_PROTO_UDP     17
#define IP_PROTO_UDPLITE 136
#define IP_PROTO_TCP     6

/** This operates on a void* by loading the first byte */
#define IP_HDR_GET_VERSION(ptr)   ((*(NX_U8*)(ptr)) >> 4)

#ifndef SHUT_RD
  #define SHUT_RD   0
  #define SHUT_WR   1
  #define SHUT_RDWR 2
#endif

/** 255.255.255.255 */
#define IPADDR_NONE         ((u32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK     ((u32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY          ((u32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST    ((u32_t)0xffffffffUL)

/** 255.255.255.255 */
#define INADDR_NONE         IPADDR_NONE
/** 127.0.0.1 */
#define INADDR_LOOPBACK     IPADDR_LOOPBACK
/** 0.0.0.0 */
#define INADDR_ANY          IPADDR_ANY
/** 255.255.255.255 */
#define INADDR_BROADCAST    IPADDR_BROADCAST

typedef NX_U32 in_addr_t;

/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED
   to prevent this code from redefining it. */
#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED)
typedef NX_U32 socklen_t;
#endif

#ifndef s_addr  //* Internet address
struct in_addr
{
    in_addr_t s_addr;
};
#define s_addr s_addr
#endif

struct ip4_addr {
  u32_t addr;
};

typedef struct ip4_addr ip_addr_t;

/*
 * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
 */
#define SO_REUSEADDR   0x0004 /* Allow local address reuse */
#define SO_KEEPALIVE   0x0008 /* keep connections alive */
#define SO_BROADCAST   0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */

/*
 * Additional options, not kept in so_options.
 */
#define SO_DEBUG        0x0001 /* Unimplemented: turn on debugging info recording */
#define SO_ACCEPTCONN   0x0002 /* socket has had listen() */
#define SO_DONTROUTE    0x0010 /* Unimplemented: just use interface addresses */
#define SO_USELOOPBACK  0x0040 /* Unimplemented: bypass hardware when possible */
#define SO_LINGER       0x0080 /* linger on close if data present */
#define SO_DONTLINGER   ((int)(~SO_LINGER))
#define SO_OOBINLINE    0x0100 /* Unimplemented: leave received OOB data in line */
#define SO_REUSEPORT    0x0200 /* Unimplemented: allow local address & port reuse */
#define SO_SNDBUF       0x1001 /* Unimplemented: send buffer size */
#define SO_RCVBUF       0x1002 /* receive buffer size */
#define SO_SNDLOWAT     0x1003 /* Unimplemented: send low-water mark */
#define SO_RCVLOWAT     0x1004 /* Unimplemented: receive low-water mark */
#define SO_SNDTIMEO     0x1005 /* send timeout */
#define SO_RCVTIMEO     0x1006 /* receive timeout */
#define SO_ERROR        0x1007 /* get error status and clear */
#define SO_TYPE         0x1008 /* get socket type */
#define SO_CONTIMEO     0x1009 /* Unimplemented: connect timeout */
#define SO_NO_CHECK     0x100a /* don't create UDP checksum */
#define SO_BINDTODEVICE 0x100b /* bind to device */

/*
 * Structure used for manipulating linger option.
 */
struct linger {
  int l_onoff;                /* option on/off */
  int l_linger;               /* linger time in seconds */
};

/*
 * Level number for (get/set)sockopt() to apply to socket itself.
 */
#define  SOL_SOCKET  0xfff    /* options for socket level */

/*
 * Options for level IPPROTO_IP
 */
#define IP_TOS             1
#define IP_TTL             2
#define IP_PKTINFO         8

/*
 * Options for level IPPROTO_TCP
 */
#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */
#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */
#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */
#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */
#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */

/*
 * Options for level IPPROTO_UDPLITE
 */
#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */
#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */

struct sockaddr_in {
  NX_U8 sin_len;
  NX_U8 sin_family;
  NX_U16 sin_port;
  struct in_addr sin_addr;
  char sin_zero[8];
};

struct sockaddr {
  NX_U8 sa_len;
  NX_U8 sa_family;
  char sa_data[14];
};

struct timeval {
    long tv_sec;         /* seconds */
    long tv_usec;        /* and microseconds */
};

uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
uint64_t htonll(uint64_t hostlonglong);
uint64_t ntohll(uint64_t netlonglong);


/** IPv4 only: get the IP address as an u32_t */
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)

int
ip4addr_aton(const char *cp, ip_addr_t *addr);
u32_t
ipaddr_addr(const char *cp);
char *
ip4addr_ntoa(const ip_addr_t *addr);
char *
ip4addr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);

#define inet_addr(cp)                   ipaddr_addr(cp)
#define inet_aton(cp, addr)             ip4addr_aton(cp, (ip_addr_t*)addr)
#define inet_ntoa(addr)                 ip4addr_ntoa((const ip_addr_t*)&(addr))
#define inet_ntoa_r(addr, buf, buflen)  ip4addr_ntoa_r((const ip_addr_t*)&(addr), buf, buflen)

#endif /* LWIP_SOCKET */

#define NET_IONREAD     0x01
#define NET_IONBIO      0x02

int NET_Socket(int domain, int type, int protocol);
NX_Error NET_Close(int socket);
NX_Error NET_Bind(int socket, struct sockaddr *addr, socklen_t addrlen);
NX_Error NET_Listen(int socket, int backlog);
NX_Error NX_Connect(int socket, struct sockaddr *addr, socklen_t addrlen);
NX_Solt NET_Accept(NX_Solt socket, struct sockaddr *addr, socklen_t *addrlen);
NX_SSize NET_Send(int socket, void *buf, int len, int flags);
NX_SSize NET_Recv(int socket, void *buf, int len, int flags);
NX_Error NET_Shutdown(int socket, int how);
NX_Error NET_Control(int socket, long cmd, void *argp);
NX_SSize NET_Sendto(int socket, void *buf, int len, int flags,
    struct sockaddr *addr, socklen_t addrlen);
NX_SSize NET_Recvfrom(int socket, void *buf, int len, int flags,
    struct sockaddr *addr, socklen_t *addrlen);
NX_Error NET_Setsockopt(int socket, int level, int optname,
    const void *optval, socklen_t optlen);
NX_Error NET_Getsockopt(int socket, int level, int optname,
    const void *optval, socklen_t *optlen);
